package manual_service

import (
	"encoding/json"
	"fmt"
	"github.com/google/uuid"
	"peilian-api/app/global/common"
	"peilian-api/app/global/databases/redisop"
	"peilian-api/app/global/databases/tables"
	"peilian-api/app/global/errors"
	"peilian-api/app/global/log"
	"peilian-api/app/global/variable"
	"peilian-api/app/model"
	"peilian-api/app/services/agent_service"
	"peilian-api/app/services/career_service"
	"peilian-api/app/services/conf_service"
	"peilian-api/app/services/user_service"
	"peilian-api/cronjob"
	"peilian-api/utils/encrypt"
	"peilian-api/utils/tools"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

func ManualOptData(ctx *gin.Context, osp model.OptionSchameParams) (interface{}, error) {
	var opt = osp.Opt
	var typ = osp.Type
	var id = osp.Id
	if opt == "schame" {
		if typ == 1 {
			agent_service.CalculationServiceTime() // 计算客户到期时间
			return "管理后台--重新计算所有客户,服务时间是否到期", nil
		}
		if typ == 2 {
			new(conf_service.ConstituteService).SetRedisConsituteKey() // 设置学校侧边栏
			return "管理后台--设置学校侧边栏", nil
		}
		if typ == 3 { // 是否开启上新题目 弹窗
			cc, _ := new(tables.CommonConf).FetchByConfKey(tables.ConfKeyTopicNew)
			redisop.SetStr(ctx, common.RedisTopicNewNotify, cc[0].ConfValue, -1)
			return "小程序--是否开启题目上新", nil
		}
		if typ == 4 {
			var cnt int64
			if err := new(career_service.CareerService).SetHistoryWebReport(ctx, &cnt); err != nil {
				log.Logger.ErrorF(ctx, err.Error())
				return "小程序&后台--处理历史的报告", nil
			}
			return fmt.Sprintf("小程序&后台--处理历史的报告, 处理数据%d条", cnt), nil
		}

	} else if opt == "trail" {
		if typ == 1 {
			SetDefaultUserTrailCount(ctx, id) // 设置 试用次数
			return fmt.Sprintf("小程序--试用次数,%d,设置成功", id), nil
		}

	} else if opt == "special" {
		if typ == 1 {
			count, err := new(career_service.CareerService).SetRedisSpecialKey() // 设置专项练习 tab bar
			if err != nil {
				return err.Err, nil
			}
			return fmt.Sprintf("小程序--设置专项练习tab bar, 处理数据%d条", count), nil
		}
		if typ == 2 {
			new(career_service.SpecialService).SetSpecialCareerList() // 设置专项练习 能力列表
			return "小程序--设置专项练习能力列表成功", nil
		}
		if typ == 3 {
			err := new(career_service.SpecialService).UpdateScore(ctx, id) // 计算某个专项练习的分数
			if err != nil {
				log.Logger.ErrorF(ctx, fmt.Sprintf("计算得分 err info: %s", err.Error()))
				return 0, err
			}
			return fmt.Sprintf("小程序--计算专项练习的分数, id: %d", id), nil
		}

	} else if opt == "es" {
		if typ == 1 {
			go cronjob.SessionDataSyncWithElasticsearch(id) // 同步用户数据到Elasticsearch
			return fmt.Sprintf("小程序--后台能力图标ES构建, id为面试场次%d", id), nil
		}

	} else if opt == "import" {
		if typ == 1 {
			if id != -100 {
				log.Logger.ErrorF(ctx, "参数error")
				return 0, nil
			}
			err := new(user_service.BdService).OptionTeacherData(ctx)
			if err != nil {
				log.Logger.ErrorF(ctx, fmt.Sprintf("导入北大教师err info: %s", err.Error()))
				return 0, err
			}
		}
	} else if opt == "token" { // 生成河北招聘网专用token
		return GenerateToken(ctx, typ, int64(id))
	} else if opt == "redis" { // 生成河北招聘网专用token
		if typ == 1 {
			return "success", LoadData(ctx)
		}
	} else if opt == "all" {
		res := map[string]map[int]interface{}{
			"schame": {
				1: []string{"计算所有客户到期时间", "/admin/update/schame?opt=schame&type=1"},
				2: []string{"设置学校侧边栏", "/admin/update/schame?opt=schame&type=2"},
				3: []string{"是否开启上新题目弹窗", "/admin/update/schame?opt=schame&type=3"},
				4: []string{"重新处理历史报告", "/admin/update/schame?opt=schame&type=4"},
			},
			"trail": {
				1: []string{"设置试用次数", "/admin/update/schame?opt=trail&type=1&id={试用次数}"},
			},
			"special": {
				1: []string{"设置专项练习tab bar", "/admin/update/schame?opt=special&type=1"},
				2: []string{"设置专项练习能力列表", "/admin/update/schame?opt=special&type=2"},
				3: []string{"重新计算某长专项练习分数", "/admin/update/schame?opt=special&type=3&id={id}"},
			},
			"es": {
				1: []string{"后台能力图标ES构建, id为面试场次id", "/admin/update/schame?opt=es&type=1&id={session_id}"},
			},
			"import": {
				1: []string{"导入北大教师信息", "/admin/update/schame?opt=import&type=1"},
			},
			"redis": {
				1: []string{"缓存数据", "/admin/update/schame?opt=redis&type=1"},
			},
			"token": {
				1: []string{"生成某个接口的token,1河北，2人大，3北航，4北理", "/admin/update/schame?opt=token&type=1"},
			},
		}
		return res, nil
	} else {
		return "params is error", nil
	}

	// if typ == 7 {
	// 	online_service.JudgeNoPcmNoMp3(ctx)
	// }

	// if typ == 8 {
	// 	s, _ := new(report_service.MaskService).MaskWords(ctx, id)
	// 	if s != "" {
	// 		return 1, nil
	// 	}
	// 	return 0, nil
	// }

	return "success", nil
}

func SetDefaultUserTrailCount(ctx *gin.Context, trailCount int) error {
	err := redisop.SetStr(ctx, common.RedisDefaultTrailCount, strconv.Itoa(trailCount), -1)
	if err != nil {
		return err
	}
	return nil
}

// token 生成
func GenerateToken(ctx *gin.Context, typ int, userId int64) (string, error) {
	uid := strconv.Itoa(int(userId))
	currentTime := time.Now().Unix()
	userInfo := struct {
		Id       string `json:"id"`
		UserName string `json:"user_name"`
		Phone    string `json:"phone"`
	}{
		Id:       uid,
		UserName: "测试test",
		Phone:    "16666666666",
	}
	cids := map[string][]string{
		//encrypt.HbKey: {variable.Config.Ex.Hb.GrantType, variable.Config.Ex.Hb.ClientId, variable.Config.Ex.Hb.AppSecret},
		//encrypt.RdKey: {variable.Config.Ex.Rd.GrantType, variable.Config.Ex.Rd.ClientId, variable.Config.Ex.Rd.AppSecret},
		//encrypt.BhKey: {variable.Config.Ex.Bh.GrantType, variable.Config.Ex.Bh.ClientId, variable.Config.Ex.Bh.AppSecret},
		//encrypt.BlKey: {variable.Config.Ex.Bl.GrantType, variable.Config.Ex.Bl.ClientId, variable.Config.Ex.Bl.AppSecret},
	}
	b, _ := json.Marshal(userInfo)
	encryptKey := encrypt.DefaultKey
	var s = ""
	sign := tools.Md5DataString(fmt.Sprintf("%s-%s-%d", variable.Config.Ex.Hb.ClientId, variable.Config.Ex.Hb.AppSecret, currentTime))
	s, _ = encrypt.RsaEncode(fmt.Sprintf("%s-%s-%s-%d-%v", cids[encryptKey][0], cids[encryptKey][1], sign, currentTime, string(b)), encryptKey)
	return s, nil
}

func LoadData(ctx *gin.Context) error {
	// 将申请的信息加载到redis
	var commonConf []tables.CommonConf
	d := variable.DB.MySQL.Model(&tables.CommonConf{}).Where("conf_key='token'").Find(&commonConf)
	if d.Error != nil {
		return fmt.Errorf("failed to load data to redis:%w", d.Error)
	}
	if len(commonConf) == 0 {
		return nil
	}
	var tokenMap map[string]model.AppSecretToken
	tokenMap = make(map[string]model.AppSecretToken, 0)
	for i := 0; i < len(commonConf); i++ {
		uid, _ := strconv.Atoi(commonConf[i].Remarks)
		tokenMap[commonConf[i].ConfValue] = model.AppSecretToken{AppSecret: commonConf[i].ExtendInfo, ClientId: commonConf[i].ConfValue, Source: commonConf[i].Other, Uid: uint(uid)}
	}
	b, _ := json.Marshal(tokenMap)
	if err := variable.DB.Redis.Set(common.RedisTokenKey, string(b), -1); err.Err() != nil {
		return fmt.Errorf(errors.LoadDataToCacheIsFail)
	}
	return nil
}

// 增加token的访问方式
func AddSchoolToken(ctx *gin.Context, req model.AddTokenReq) (model.EnterpriseKey, error) {
	var ek model.EnterpriseKey
	// 修改参数 account_name 中不能包含- 会和token解析混淆 - 改成_
	req.AccountName = strings.ReplaceAll(req.AccountName, "-", "_")

	// 查询学校是否存在
	schools := new(tables.School).GetSchoolByName(req.School)
	if len(schools) != 1 {
		return ek, fmt.Errorf("学校名字错误")
	}
	// 添加agent 信息
	agentObj := new(tables.Agent)
	var agents []tables.Agent
	err := variable.DB.MySQL.Model(tables.Agent{}).Where("school = ? or id = ?", req.School, req.AgentId).Find(&agents).Error
	if err != nil {
		return ek, fmt.Errorf(errors.DatabaseMySqlOptionFail)
	}
	var agent tables.Agent
	if len(agents) > 0 {
		agent = agents[0]
	} else {
		startTime := time.Now()
		endTime := time.Now().Add(365 * 24 * time.Hour)
		surplusTime := tools.DiffNatureDays(endTime, time.Now())
		startTime, _ = time.Parse("2006-01-02 15:04:05", startTime.Format("2006-01-02")+" 23:59:59")
		endTime, _ = time.Parse("2006-01-02 15:04:05", endTime.Format("2006-01-02")+" 23:59:59")
		if surplusTime <= 0 {
			surplusTime = 0
		}
		agent, err = agentObj.AddAgent(tables.Agent{
			Type:             "school",
			Email:            uuid.New().String() + "@manual.com",
			AgentName:        req.School,
			ConnectPeople:    "赵琳",
			ConnectPhone:     "",
			Counterpart:      "赵琳",
			CounterpartPhone: "",
			ServiceStartTime: startTime,
			ServiceEndTime:   endTime,
			School:           req.School,
			SurplusTime:      int64(surplusTime),
			IsSync:           false,
		})
	}

	// 更新一下缓存数据
	loc := time.FixedZone("UTC+8", 8*60*60)
	t, _ := time.ParseInLocation("2006-01-02 15:04:05", agent.ServiceEndTime.Format("2006-01-02")+" 23:59:59", loc)
	variable.DB.Redis.Set(fmt.Sprintf(common.RedisAgentIsTimeoutKey, agent.ID), t.Unix(), -1)
	// 插入Constitute
	cont, err := new(tables.Constitute).GetInfoByWhere(map[string]interface{}{"name": req.School, "type": tables.SchoolType})
	if err != nil {
		return ek, fmt.Errorf(errors.DatabaseMySqlOptionFail)
	}
	if cont.ID == 0 {
		if _, err := new(tables.Constitute).InsertInfo(tables.Constitute{Name: req.School, Type: tables.SchoolType, AgentID: &(agent.ID)}); err != nil {
			return ek, fmt.Errorf(errors.DatabaseMySqlOptionFail)
		}
		cont, _ = new(tables.Constitute).GetInfoByWhere(map[string]interface{}{"name": req.School, "type": tables.SchoolType})
	}

	// 查询account 是否重复
	us, err := new(tables.User).GetUsersByWhere(map[string]interface{}{"account_name": req.AccountName}, "*")
	if err != nil {
		return ek, fmt.Errorf("user select error: %+v", err)
	}
	if len(us) != 0 {
		return ek, fmt.Errorf("user account_name has exist")
	}
	name := req.School
	// 添加用户信息
	u := tables.User{
		Name:        name + "-Token用户",
		Password:    "",
		AccountName: &req.AccountName,
		Type:        tables.UserTypeEnterprise,
		School:      req.School,
		AgentID:     agent.ID,
		Level:       tables.RolesLevel2,
		RoleId:      tables.RolesLevel2,
		IsSync:      true,
		IsUpdatePwd: false,
	}
	d := variable.DB.MySQL.Create(&u)
	if err := d.Error; err != nil {
		return ek, fmt.Errorf(err.Error())
	}
	// 添加数据,
	appKey := tools.RandStringLowBytes(18)
	appSecret := tools.RandStringDigitBytes(27)
	cc := tables.CommonConf{}
	cc.ConfValue = fmt.Sprintf("%s_%s", req.AccountName, appKey)
	cc.ExtendInfo = fmt.Sprintf("app_%s", appSecret)
	cc.Remarks = strconv.Itoa(int(u.ID))
	cc.Other = req.AccountName
	cc.Type = 1
	cc.ConfKey = "token"
	d2 := variable.DB.MySQL.Create(&cc)
	if err := d2.Error; err != nil {
		return ek, fmt.Errorf(err.Error())
	}
	ek.AppKey = cc.ConfValue
	ek.AppSecret = cc.ExtendInfo
	_ = LoadData(ctx)
	return ek, nil
}
